home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / New System Software Extensions / QuickDraw™ GX v1.0ß2 / Goodies / ColorPicker 2.0a6 / ExamplePicker / Example.c next >
Encoding:
C/C++ Source or Header  |  1992-10-08  |  27.7 KB  |  1,132 lines  |  [TEXT/MPS ]

  1. /*
  2. *        A sample color picker.
  3. *
  4. *        Written by: Shannon Holland
  5. *        March 2, 1992
  6. *
  7. */
  8.  
  9. #define SystemSevenOrLater 1
  10.  
  11. #include <Memory.h>
  12. #include <Sysequ.h>
  13. #include <QDOffscreen.h>
  14. #include <FixMath.h>
  15. #include <ToolUtils.h>
  16. #include <SANE.h>
  17. #include <Resources.h>
  18. #include <Controls.h>
  19. #include <Windows.h>
  20. #include <Dialogs.h>
  21. #include <Timer.h>
  22. #include <Packages.h>
  23. #include <strings.h>
  24. #include <TextEdit.h>
  25. #include <Fonts.h>
  26. #include <Script.h>
  27. #include <GestaltEqu.h>
  28. #include <CMApplication.h>
  29.  
  30. #include "ColorPicker.h"
  31. #include "ColorPickerComponentPublic.h"
  32. #include "Example.h"
  33.  
  34.  
  35.  
  36. #define        RectWidth(x)        ((x).right - (x).left)
  37. #define        RectHeight(x)        ((x).bottom - (x).top)
  38. #define        ChangeBigEnough(x,y)    (abs(x - y) > 6)
  39.  
  40. /*
  41. *    Determine which routine to dispatch to and then ask the component manager to call that
  42. *    routine with our storage handle and all of its parameters set up nicely.
  43. */
  44. pascal ComponentResult ExampleMain(ComponentParameters *params, Handle storage)
  45. {
  46. short message;
  47. ComponentResult result;
  48. ComponentFunction RoutineToCall = 0;
  49.  
  50.     message = params->what;
  51.     if (message < 0)
  52.         // negative values are component manager messages
  53.         switch (message)
  54.         {
  55.             case    kComponentOpenSelect:        RoutineToCall=ExampleOpen;        break;
  56.             case    kComponentCloseSelect:        RoutineToCall=ExampleClose;        break;
  57.             case    kComponentCanDoSelect:        RoutineToCall=ExampleCanDo;        break;
  58.             case    kComponentVersionSelect:    RoutineToCall=ExampleVersion;    break;
  59.             case    kComponentRegisterSelect:    RoutineToCall=ExampleRegister;    break;
  60.             case    kComponentTargetSelect:        RoutineToCall=ExampleSetTarget;    break;
  61.             default:    return 0;        // no error
  62.         }
  63.     else
  64.     {
  65.         switch (message)
  66.         {
  67.             case    kInitPicker:                RoutineToCall=ExampleInitPicker;                break;
  68.             case    kTestGraphicsWorld:            RoutineToCall=ExampleTestGraphicsWorld;            break;
  69.             case    kGetDialog:                    RoutineToCall=ExampleGetDialog;                    break;
  70.             case    kGetItemList:                RoutineToCall=ExampleGetItemList;                break;
  71.             case    kGetColor:                    RoutineToCall=ExampleGetColor;                    break;
  72.             case    kSetColor:                    RoutineToCall=ExampleSetColor;                    break;
  73.             case    kEvent:                        RoutineToCall=ExampleDoEvent;                    break;
  74.             case    kEdit:                        RoutineToCall=ExampleDoEdit;                    break;
  75.             case    kSetVisibility:                RoutineToCall=ExampleSetVisibility;                break;
  76.             case    kDrawPicker:                RoutineToCall=ExampleDisplayPicker;                break;
  77.             case    kItemHit:                    RoutineToCall=ExampleItemHit;                    break;
  78.             case    kSetBaseItem:                RoutineToCall=ExampleSetBaseItem;                break;
  79.             case    kGetProfile:                RoutineToCall=ExampleGetProfile;                break;
  80.             case    kSetProfile:                RoutineToCall=ExampleSetProfile;                break;
  81.             case    kGetPrompt:                    RoutineToCall=ExampleGetPrompt;                    break;
  82.             case    kSetPrompt:                    RoutineToCall=ExampleSetPrompt;                    break;
  83.             case    kGetIconData:                RoutineToCall=ExampleGetIconData;                break;
  84.             case    kGetEditMenuState:            RoutineToCall=ExampleGetEditMenuState;            break;
  85.             case    kSetOrigin:                    RoutineToCall=ExampleSetOrigin;                    break;
  86.             case    kExtractHelpItem:            RoutineToCall=ExampleExtractHelpItem;            break;
  87.             default:    return 0;
  88.         }
  89.     }
  90.     result=CallComponentFunctionWithStorage(storage, params, RoutineToCall);
  91.  
  92.     return result;
  93. }
  94.  
  95. /*
  96. *    open our instance. We allocate our storage handle here but do not allocate anything inside it.
  97. *    This is because we aren't necessarily being opened for real (but just for addition to the More
  98. *    Choices list, etc.). We probably should not even allocate our storage handle here, but wait
  99. *    for the InitPicker message.
  100. */
  101. pascal ComponentResult ExampleOpen(PickerStorageHndl storage, ComponentInstance self)
  102. {
  103.     
  104.     storage = (PickerStorageHndl) NewHandle(sizeof(PickerStorage));
  105.     SetComponentInstanceStorage(self,(Handle) storage);
  106.     (*storage)->myself=self;        // store reference to self
  107.     (*storage)->realPicker = false;    // we're not real yet
  108.     
  109.     return 0;
  110. }
  111.  
  112. pascal ComponentResult ExampleClose(PickerStorageHndl storage, ComponentInstance self)
  113. {
  114. #pragma unused (self)
  115.  
  116.     // if we have been opened for real, dispose of our private data
  117.     if((*storage)->realPicker)  {
  118.         DisposPixPat((*storage)->newColorPat);
  119.         DisposPixPat((*storage)->origColorPat);
  120.         DisposHandle((Handle) (*storage)->profile);
  121.     }
  122.         
  123.     DisposHandle((Handle) storage);        // remove all storage
  124.  
  125.     return noErr;
  126. }
  127.  
  128. pascal ComponentResult ExampleCanDo(PickerStorageHndl storage, short selector)
  129. {
  130. #pragma unused (storage)
  131.  
  132.     if ((selector >= kComponentTargetSelect) && (selector <= kComponentOpenSelect))
  133.         return true;
  134.     if ((selector >= kInitPicker) && (selector <= kSetOrigin))
  135.         return true;
  136.     
  137.     return false;
  138. }
  139.  
  140. pascal ComponentResult ExampleVersion(PickerStorageHndl storage)
  141. {
  142. #pragma unused (storage)
  143.  
  144.     return 0;
  145. }
  146.  
  147. pascal ComponentResult ExampleRegister(PickerStorageHndl storage)
  148. {
  149. #pragma unused (storage)
  150.  
  151.     return noErr;            // always register
  152. }
  153.  
  154. pascal ComponentResult ExampleSetTarget(PickerStorageHndl storage, ComponentInstance topOfCallChain)
  155. {
  156. #pragma unused (storage,topOfCallChain)
  157.  
  158.     return 0;
  159. }
  160.  
  161. /*
  162. *    Test the machine state and picker supplied instance flags (restrictions) to check to see if
  163. *    we can live here. If not, return an error.
  164. */
  165. pascal long ExampleTestGraphicsWorld(PickerStorageHndl storage,PickerInitData *data)
  166. {
  167. #pragma unused(storage,data)
  168. OSErr err = noErr;
  169. long gLong;
  170.     
  171.     // we require at least Color QuickDraw
  172.     
  173.     Gestalt(gestaltQuickdrawVersion,&gLong);
  174.     
  175.     return gLong >= gestalt8BitQD ? noErr : pickerCantLive;
  176. }
  177.  
  178. pascal ComponentResult ExampleInitPicker(PickerStorageHndl storage,PickerInitData *data)
  179. {
  180. GrafPtr thePort;
  181. OSErr error = noErr;
  182. PMColorPtr theColor;
  183. RGBColor rgb;
  184. short resFile;
  185.     
  186.     // open our resource file
  187.     resFile = OpenComponentResFile((Component) (*storage)->myself);
  188.  
  189.     GetPort(&thePort);
  190.     (*storage)->port = thePort;
  191.     (*storage)->flags = data->flags;
  192.     
  193.     (*storage)->realPicker = true;
  194.     
  195.     // we're always opened invisible
  196.     (*storage)->visible = false;
  197.     
  198.     (*storage)->active = true;
  199.     
  200.     // initalise our internal colors
  201.     theColor = &(*storage)->color;
  202.     theColor->profile = 0;
  203.     theColor->color.rgb.red = 0;
  204.     theColor->color.rgb.green = 0;
  205.     theColor->color.rgb.blue = 0;
  206.     (*storage)->origColor = (*storage)->color;
  207.     (*storage)->lastRGB = (*storage)->color.color.rgb;
  208.  
  209.     InitNumerics(storage);
  210.  
  211.     // allocate patterns for the color rectangles
  212.     (*storage)->newColorPat = NewPixPat();
  213.     (*storage)->origColorPat = NewPixPat();
  214.     
  215.     // and initialise them to the current color
  216.     rgb = (*storage)->color.color.rgb;
  217.     MakeRGBPat((*storage)->newColorPat,&rgb);
  218.     
  219.     rgb = (*storage)->origColor.color.rgb;
  220.     MakeRGBPat((*storage)->origColorPat,&rgb);
  221.     
  222.     (*storage)->profile = 0L;
  223.     
  224. finish:
  225.     CloseComponentResFile(resFile);
  226.     
  227.     return error;
  228. }
  229.  
  230. /*
  231. *    Return a pointer to our private dialog if we have one. This example does not, so we
  232. *    return nil.
  233. */
  234. pascal ComponentResult ExampleGetDialog(PickerStorageHndl storage)
  235. {
  236. #pragma unused (storage)
  237.  
  238.     // if you did have a dialog, you would open up your resource file,
  239.     // open up the dialog and detach any private resources that were grabbed from
  240.     // your file (such as the WDEF if you had a private one).
  241.     
  242.     return 0L;
  243. }
  244.  
  245. /*
  246. *    Return a handle to the picker's item list. If the picker saved it as a resource, it is
  247. *    the picker's responsibility to detach it
  248. */
  249. pascal long ExampleGetItemList(PickerStorageHndl storage)
  250. {
  251. #pragma unused (storage)
  252. Handle theItems;
  253. short resFile;
  254.     
  255.     // open our resource file so we can get our DITL
  256.     resFile = OpenComponentResFile((Component) (*storage)->myself);
  257.     
  258.     // get the DITL and detach it so it won't go away when we close the file
  259.     theItems = GetResource('DITL',kPickerDITL);
  260.     if(theItems)
  261.         DetachResource(theItems);
  262.     
  263.     // close the file
  264.     CloseComponentResFile(resFile);
  265.     
  266.     return (long) theItems;
  267. }
  268.  
  269. /*
  270. *    Get the current original or new color
  271. */
  272. pascal ComponentResult ExampleGetColor(PickerStorageHndl storage,ColorType whichColor,PMColorPtr color)
  273. {
  274.     // we can copy the color here because the profile is always set to what we want it to be
  275.     // (nil - the system profile/rgb space).
  276.     if(whichColor == kNewColor)
  277.         *color = (*storage)->color;
  278.     else
  279.         *color = (*storage)->origColor;
  280.  
  281.  
  282.     return noErr;
  283. }
  284.  
  285. /*
  286. *    Set the current original or new color.
  287. */
  288. pascal ComponentResult ExampleSetColor(PickerStorageHndl storage,ColorType whichColor,PMColorPtr color)
  289. {
  290. Boolean updateEditor = false;
  291. Boolean textInvalid = false;
  292. CWorld cworld;
  293. PMColor myColor;
  294. long csLong;
  295. OSErr err = noErr;
  296.  
  297.     myColor = *color;        // get our own copy
  298.  
  299.     // check to see if a profile was included, if so, convert the color to system space
  300.     if(color->profile)  {
  301.         // first make sure that ColorSync is around
  302.         if(Gestalt(gestaltColorMatchingVersion,&csLong) != noErr)  {
  303.             err = colorSyncNotInstalled;
  304.             goto fail;
  305.         }
  306.         
  307.         // now create the color world and convert the color
  308.         if(CWNewColorWorld(&cworld,myColor.profile,0L) == noErr)  {
  309.             if(CWMatchColors(cworld,&myColor.color,1) != noErr)  {
  310.                 err = badProfileError;
  311.                 CWDisposeColorWorld(cworld);
  312.                 goto fail;
  313.             }
  314.             CWDisposeColorWorld(cworld);
  315.         } else  {
  316.             err = badProfileError;
  317.             goto fail;
  318.         }
  319.     }
  320.     myColor.profile = 0L;        // it's in the system space now
  321.     
  322.     if(whichColor == kNewColor)  {
  323.         (*storage)->color = *color;
  324.         (*storage)->lastRGB = color->color.rgb;
  325.         updateEditor = true;
  326.     } else  {
  327.         (*storage)->origColor = *color;
  328.         
  329.         // make a new pattern for the original color
  330.         MakeRGBPat((*storage)->origColorPat,&color->color.rgb);
  331.         if((*storage)->visible)
  332.             DrawColorRects(storage,true);    // redraw the original color rectangle
  333.     }
  334.     
  335.     if(updateEditor)  {
  336.         // make some internal calls to update data structures and redraw the parts of the picker
  337.         // that need it
  338.         SetSelectionColor(storage);
  339.         UpdateColorText(storage);
  340.         
  341.         if((*storage)->visible)  {
  342.             // we don't call DoPickerDraw here as we don't need to redraw everything!
  343.             DrawColorRects(storage,false);
  344.             DrawColorEditor(storage,false);
  345.         }
  346.     }
  347. fail:
  348.     return err;
  349. }
  350.  
  351. /*
  352. *    Change our visibility status
  353. */
  354. pascal ComponentResult ExampleSetVisibility(PickerStorageHndl storage,Boolean visible)
  355. {
  356.  
  357.     (*storage)->visible = visible;
  358.  
  359.     return 0L;
  360. }
  361.  
  362. /*
  363. *    Redraw the picker (in response to an update event).
  364. */
  365. pascal ComponentResult ExampleDisplayPicker(PickerStorageHndl storage)
  366. {
  367.     
  368.     if((*storage)->visible)  {
  369.         DrawColorList(storage);
  370.         DrawColorEditor(storage,true);
  371.     }
  372.  
  373.     return noErr;
  374. }
  375.  
  376. /*
  377. *    Do any special preprocessing for events that we need to do.
  378. */
  379. pascal ComponentResult ExampleDoEvent(PickerStorageHndl storage,EventData *data)
  380. {
  381. OSErr err = noErr;
  382.  
  383.     // initialise to not filter
  384.     data->handled = false;
  385.     data->action = kDidNothing;
  386.     
  387.     if(data->event)  {
  388.         switch(data->event->what)  {
  389.             case nullEvent:
  390.                 DoIdle(storage,data);
  391.                 break;
  392.             case mouseDown:
  393.                 err = DoMouseDown(storage,data);
  394.                 break;
  395.             case keyDown:
  396.             case autoKey:
  397.                 err = DoKeyDown(storage,data);
  398.                 break;
  399.             case keyUp:
  400.                 err = DoKeyUp(storage,data);
  401.                 break;
  402.             case activateEvt:
  403.                 if(data->event->modifiers & activeFlag)
  404.                     ActivatePicker(storage);
  405.                 else
  406.                     DeactivatePicker(storage);
  407.                 break;
  408.         }    
  409.     }
  410.     return err;
  411. }
  412.  
  413. /*
  414. *    Handle edit operations. We let the picker manager handle everything for us, except undo.
  415. */
  416. pascal ComponentResult ExampleDoEdit(PickerStorageHndl storage,EditData *data)
  417. {
  418. RGBColor rgb;
  419.  
  420.     switch(data->theEdit)  {
  421.         default:
  422.             // default behaviour is ok
  423.             data->action = kDidNothing;
  424.             data->handled = false;
  425.             break;
  426.         case kUndo:
  427.             // do the undo thing
  428.             rgb = (*storage)->lastRGB;
  429.             (*storage)->lastRGB = (*storage)->color.color.rgb;
  430.             (*storage)->color.color.rgb = rgb;
  431.             
  432.             // update the other internal data and then redraw
  433.             SetSelectionColor(storage);
  434.             UpdateColorText(storage);
  435.             DrawColorRects(storage,false);
  436.  
  437.             data->action = kColorChanged;
  438.             data->handled = true;
  439.             break;
  440.     }
  441.     return noErr;
  442. }
  443.  
  444. /*
  445. *    The dialog manager said that one of our items was hit, so find out which one
  446. *    it was and do the right thing.
  447. */
  448. pascal long ExampleItemHit(PickerStorageHndl storage,ItemHitData *data)
  449. {
  450. #pragma unused(iMod)
  451.  
  452. Handle theItem;
  453. short iType;
  454. Rect iBox;
  455. OSErr err = noErr;
  456.         
  457.     data->action = kDidNothing;
  458.  
  459.     GetDItem((*storage)->port,(*storage)->baseItem + data->itemHit,&iType,&theItem,&iBox);
  460.         
  461.     switch(data->itemHit)  {
  462.         case iRedText:
  463.         case iGreenText:
  464.         case iBlueText:
  465.             // don't udpate everything as the user types each key, just do it when they
  466.             // leave a field
  467.             if(data->iMod != kKeyDown && data->itemHit != kMouseDown)
  468.                 CheckCurrentWorld(storage,data->itemHit);
  469.             break;
  470.         case iOrigColor:
  471.             err = DoListClick(storage,data);
  472.             break;
  473.         case iNewColor:
  474.             break;
  475.     }    
  476.     return err;
  477. }
  478.  
  479. /*
  480. *    Set the base item for the color picker's items. This allows us to get at our items
  481. *    through the dialog manager. RealItemNumber = baseItem + locaItemNumber (1 based).
  482. */
  483. pascal long ExampleSetBaseItem(PickerStorageHndl storage,short baseItem)
  484. {
  485.     (*storage)->baseItem = baseItem;
  486.     
  487.     return noErr;
  488. }
  489.  
  490. /*
  491. *    Get the current destination profile our picker is using
  492. */
  493. pascal long ExampleGetProfile(PickerStorageHndl storage)
  494. {
  495. Handle h;
  496.  
  497.     // return a copy of the profile
  498.     h = (Handle) (*storage)->profile;
  499.     if(h)
  500.         HandToHand(&h);
  501.     
  502.     return (long) h;
  503. }
  504.  
  505. /*
  506. *    Set the current destination profile.
  507. */
  508. pascal long ExampleSetProfile(PickerStorageHndl storage,CMProfileHandle profile)
  509. {
  510. CMProfileHandle myProfile;
  511. OSErr err = noErr;
  512.  
  513.     // make a private copy of the profile. We need to do this even though this
  514.     // picker doesn't do anything with profiles because the picker manager relies
  515.     // on us to store this data so that it doesn't have to duplicate the storage
  516.     // and waste lots of memory
  517.     
  518.     if(myProfile = profile)  {
  519.         HandToHand((Handle *) &myProfile);
  520.         if((err = MemError()) != noErr)
  521.             goto fail;
  522.     }
  523.     (*storage)->profile = myProfile;
  524.  
  525. fail:
  526.     return err;
  527. }
  528.  
  529. /*
  530. *    Get the contents of our prompt
  531. */
  532. pascal long ExampleGetPrompt(PickerStorageHndl storage,Str255 prompt)
  533. {
  534. Handle theItem;
  535. short iType;
  536. Rect iBox;
  537.             
  538.     GetDItem((*storage)->port,(*storage)->baseItem + iPrompt,&iType,&theItem,&iBox);
  539.     GetIText(theItem,prompt);
  540.     
  541.     return noErr;
  542. }
  543.  
  544. /*
  545. *    Set the contents of our prompt
  546. */
  547. pascal long ExampleSetPrompt(PickerStorageHndl storage,Str255 prompt)
  548. {
  549. Handle theItem;
  550. short iType;
  551. Rect iBox;
  552.             
  553.     GetDItem((*storage)->port,(*storage)->baseItem + iPrompt,&iType,&theItem,&iBox);
  554.     SetIText(theItem,prompt);
  555.     
  556.     return noErr;
  557. }
  558.  
  559. /*
  560. *    Return the data that the picker manager needs for our picker in the More Choices
  561. *    List - our script code and the resource id of our icon suite.
  562. */
  563. pascal long ExampleGetIconData(PickerStorageHndl storage,PickerIconData *data)
  564. {
  565. short fref;
  566. OSErr err = noErr;
  567. PickerIconData **mypdat;
  568.  
  569.     data->scriptCode = 0;
  570.     data->iconSuiteID = kPickerData;
  571.     
  572.     fref = OpenComponentResFile((Component) (*storage)->myself);
  573.     if(fref)  {
  574.         mypdat = (PickerIconData **) GetResource(kPickerDataType,kPickerData);
  575.         if(mypdat)
  576.             *data = **mypdat;
  577.         else
  578.             goto fail;
  579.     } else
  580.         goto fail;
  581.         
  582.     CloseComponentResFile(fref);
  583.     
  584.     return err;
  585.  
  586. fail:
  587.     DebugStr("\pProblem getting resource");
  588.     
  589.     return pickerResourceError;
  590. }
  591.  
  592. /*
  593. *    Specify how we want the edit menu to be set
  594. */
  595. pascal long ExampleGetEditMenuState(PickerStorageHndl storage,MenuState *mState)
  596. {
  597. #pragma unused(storage)
  598.  
  599. OSErr err = noErr;
  600.  
  601.     mState->cutEnabled = true;
  602.     mState->copyEnabled = true;
  603.     mState->pasteEnabled = true;
  604.     mState->clearEnabled = true;
  605.     mState->undoEnabled = true;
  606.     strcpy(mState->undoString,"\pUndo");
  607.     
  608.     return err;
  609. }
  610.  
  611.  
  612. /*
  613. *    We've been moved to the specified origin. Update any internal data structures here.
  614. *    All of our dialog items will have been moved for us.
  615. */
  616. pascal long ExampleSetOrigin(PickerStorageHndl storage,Point where)
  617. {
  618. #pragma unused(storage,where)
  619.  
  620.     // we don't have anything that needs moving
  621.     
  622.     return noErr;
  623. }
  624.  
  625. /*
  626. *    The picker manager is about to put up a help balloon for a given item. If we want to overide
  627. *    any help resources that we have, we should store the help item info in helpInfo and return
  628. *    noErr. Otherwise return noHelpForItem and the default behaviour will take place.
  629. */
  630. pascal long ExampleExtractHelpItem(PickerStorageHndl storage,short itemNo,short whichState,HelpItemInfo *helpInfo)
  631. {
  632. #pragma unused(storage,itemNo,whichState,helpInfo)
  633.  
  634.     return noHelpForItem;
  635. }
  636.  
  637.  
  638.  
  639. /****************************************************************************************************
  640. *
  641. *    Private routines begin here
  642. *
  643. ****************************************************************************************************/
  644.  
  645.  
  646. /*
  647. *    Do anything special for a mousedown event.
  648. */
  649. OSErr DoMouseDown(PickerStorageHndl storage,EventData *data)
  650. {
  651. #pragma unused (storage,data)
  652.     
  653.     // set data->handled to true if we handled the event
  654.     
  655.     return noErr;
  656. }
  657.  
  658. /*
  659. *    Do anything special for a keydown event.
  660. */
  661. OSErr DoKeyDown(PickerStorageHndl storage,EventData *data)
  662. {
  663. short key;
  664. Boolean optKeyDown,cmdKeyDown,itemOurs;
  665. short theItem;
  666.     
  667.     // check that the current edit item is ours and that the command and option keys are
  668.     // not down before we do any key masking
  669.     
  670.     theItem = ((DialogPeek) (*storage)->port)->editField + 1 - (*storage)->baseItem;
  671.     optKeyDown = (data->event->modifiers & optionKey) != 0;
  672.     cmdKeyDown = (data->event->modifiers & cmdKey) != 0;
  673.     itemOurs = theItem > 0 && theItem <= iLastItem;
  674.     
  675.     if(!optKeyDown && !cmdKeyDown && itemOurs)  {
  676.         key = data->event->message & charCodeMask;
  677.         switch(key)  {
  678.             case kUpArrow:
  679.             case kDnArrow:
  680.             case kLtArrow:
  681.             case kRtArrow:
  682.             case '.':
  683.             case kBackSpace:
  684.             case kTab:
  685.                 // these keys are all ok
  686.                 break;
  687.         
  688.             case kReturn:
  689.             case kEnter:
  690.                 // make sure we update everything
  691.                 CheckCurrentWorld(storage,iRedText);
  692.                 CheckCurrentWorld(storage,iGreenText);
  693.                 CheckCurrentWorld(storage,iBlueText);
  694.                 break;
  695.             default:
  696.                 // check that the key was numeric, otherwise beep and handle the keydown
  697.                 // note that this is not internationally kosher! (that's why this is an example!)
  698.                 if(key < '0' || key > '9')  {
  699.                     SysBeep(1);
  700.                     data->handled = true;
  701.                 }
  702.                 break;
  703.         }
  704.     }
  705.     
  706.     return noErr;
  707. }
  708.  
  709. /*
  710. *    Do anything special for a keyup event.
  711. */
  712. OSErr DoKeyUp(PickerStorageHndl storage,EventData *data)
  713. {
  714. #pragma unused (storage,data)
  715.  
  716.     return noErr;
  717. }
  718.  
  719. /*
  720. *    Do anything special for a null event.
  721. */
  722. OSErr DoIdle(PickerStorageHndl storage,EventData *data)
  723. {
  724. #pragma unused (storage,data)
  725.  
  726.     return noErr;
  727. }
  728.  
  729. /*
  730. *    Handle an activate event.
  731. */
  732. void ActivatePicker(PickerStorageHndl storage)
  733. {
  734.     (*storage)->active = true;
  735. }
  736.  
  737. /*
  738. *    Handle an deactivate event.
  739. */
  740. void DeactivatePicker(PickerStorageHndl storage)
  741. {
  742.     (*storage)->active = false;
  743. }
  744.  
  745. /*
  746. *    check the item "itemNo" to see if it's changed. If it has, then update
  747. *    the current color and recreate the item's string so that it looks pretty.
  748. *    We use a macro CheckBigEnough to make sure that the difference between
  749. *    string and number is greater than the error in the string representation.
  750. */
  751. void CheckCurrentWorld(PickerStorageHndl storage,short itemNo)
  752. {
  753. Str255 itemStr;
  754. Handle theItem;
  755. long value;
  756. Boolean drawWheel = false,newColor = false;
  757.  
  758.     theItem = GetItemHandle(storage,itemNo);
  759.     switch(itemNo)  {
  760.         case iRedText:
  761.             GetIText(theItem,itemStr);
  762.             if(PercentageToNum(storage,itemStr,&value) && ChangeBigEnough(value,(*storage)->color.color.rgb.red))  {
  763.                 (*storage)->lastRGB = (*storage)->color.color.rgb;
  764.                 (*storage)->color.color.rgb.red = value;
  765.                 newColor = true;
  766.             }
  767.             break;
  768.         case iGreenText:
  769.             GetIText(theItem,itemStr);
  770.             if(PercentageToNum(storage,itemStr,&value) && ChangeBigEnough(value,(*storage)->color.color.rgb.green))  {
  771.                 (*storage)->lastRGB = (*storage)->color.color.rgb;
  772.                 (*storage)->color.color.rgb.green = value;
  773.                 newColor = true;
  774.             }
  775.             break;
  776.         case iBlueText:
  777.             GetIText(theItem,itemStr);
  778.             if(PercentageToNum(storage,itemStr,&value) && ChangeBigEnough(value,(*storage)->color.color.rgb.blue))  {
  779.                 (*storage)->lastRGB = (*storage)->color.color.rgb;
  780.                 (*storage)->color.color.rgb.blue = value;
  781.                 newColor = drawWheel = true;
  782.             }
  783.             break;
  784.     }
  785.     if(newColor)  {
  786.         SetSelectionColor(storage);
  787.         UpdateColorText(storage);
  788.     }
  789. }
  790.  
  791. /*
  792. *    Update the text fields based on string comparisons of the current internal color (numeric)
  793. *    to the contents of the dialog items.
  794. */
  795. void UpdateColorText(PickerStorageHndl storage)
  796. {
  797. Str255 numStr,itemStr;
  798. Handle theItem;
  799. short iType;
  800. short itemNo;
  801. Rect iBox;
  802.         
  803.     TextMode(srcCopy);
  804.     ForeColor(blackColor);
  805.     BackColor(whiteColor);
  806.     
  807.     // Red
  808.     
  809.     GetDItem((*storage)->port,(*storage)->baseItem + iRedText,&iType,&theItem,&iBox);
  810.     NumToPercentage(storage,(*storage)->color.color.rgb.red,numStr);
  811.     numStr[numStr[0] + 1] = '\0';
  812.     GetIText(theItem,itemStr);
  813.     itemStr[itemStr[0] + 1] = '\0';
  814.     
  815.     if(strcmp(itemStr,numStr) != 0)
  816.         SetIText(theItem,numStr);
  817.     
  818.     // Green
  819.     
  820.     GetDItem((*storage)->port,(*storage)->baseItem + iGreenText,&iType,&theItem,&iBox);
  821.     NumToPercentage(storage,(*storage)->color.color.rgb.green,numStr);
  822.     numStr[numStr[0] + 1] = '\0';
  823.     GetIText(theItem,itemStr);
  824.     itemStr[itemStr[0] + 1] = '\0';
  825.     
  826.     if(strcmp(itemStr,numStr) != 0)
  827.         SetIText(theItem,numStr);
  828.     
  829.     // Blue
  830.     
  831.     GetDItem((*storage)->port,(*storage)->baseItem + iBlueText,&iType,&theItem,&iBox);
  832.     NumToPercentage(storage,(*storage)->color.color.rgb.blue,numStr);
  833.     numStr[numStr[0] + 1] = '\0';
  834.     GetIText(theItem,itemStr);
  835.     itemStr[itemStr[0] + 1] = '\0';
  836.  
  837.     if(strcmp(itemStr,numStr) != 0)
  838.         SetIText(theItem,numStr);
  839.     
  840.     // now select the current text item (if it's ours...)
  841.     
  842.     itemNo = ((DialogPeek) (*storage)->port)->editField + 1 - (*storage)->baseItem;
  843.     if(itemNo > 0 && itemNo >= iLastItem)
  844.         SelIText((*storage)->port,itemNo,0,32767);
  845. }
  846.  
  847. /*
  848. *    Convert a value to a percentage of 65536 and write it as a string to theString. We use
  849. *    the script manager cuz we're nice.
  850. */
  851. void NumToPercentage(PickerStorageHndl storage,long value,char *theString)
  852. {
  853. short fResult;
  854.  
  855.     HLock((Handle) storage);
  856.     
  857.     fResult = FormatX2Str(value / 65535.0 * 100.0,&(*storage)->nFormat,&(*storage)->nParts,theString);
  858.     if(fResult != fFormatOK)
  859.         DebugStr("\pBad format");
  860.     
  861.     HUnlock((Handle) storage);
  862. }
  863.  
  864. /*
  865. *    Convert a percentage string (percentage of 65535) to a number. Return true if the script
  866. *    manager was able to successfuly convert, false otherwise (ie the string was not a number).
  867. */
  868. Boolean PercentageToNum(PickerStorageHndl storage,char *theString,long *theNum)
  869. {
  870. extended x;
  871. FormatStatus fResult;
  872. Boolean isValid = false;
  873.     
  874.     HLock((Handle) storage);
  875.     fResult = FormatStr2X((ConstStr255Param) theString,&(*storage)->nFormat,&(*storage)->nParts,&x);
  876.     HUnlock((Handle) storage);
  877.  
  878.     switch(fResult)  {
  879.         case fFormatOK:
  880.         case fBestGuess:
  881.         case fOutOfSynch:
  882.         case fSpuriousChars:
  883.         case fMissingDelimiter:
  884.         case fExtraDecimal:
  885.         case fMissingLiteral:
  886.         case fExtraExp:
  887.         case fExtraPercent:
  888.         case fExtraSeparator:
  889.         case fEmptyFormatString:
  890.             isValid = true;
  891.             break;
  892.         default:
  893.             break;
  894.     }    
  895.     if(isValid)  {
  896.         *theNum = x * 65535.0 / 100.0;
  897.         if(*theNum > 65535)
  898.             *theNum = 65535;
  899.         else if(*theNum < 0)
  900.             *theNum = 0;
  901.     }
  902.     return isValid;
  903. }
  904.  
  905. /*
  906. *    Handle a click in the original and new color rectangles. If the user has clicked
  907. *    in the original color box, we want to make that color the new collor.
  908. */
  909. OSErr DoListClick(PickerStorageHndl storage,ItemHitData *data)
  910. {
  911. Rect origColorRect;
  912. Boolean inBox,lastInBox;
  913. PMColor origTemp,newTemp;
  914. Point where;
  915. PMColor newColor;
  916. OSErr err = noErr;
  917.     
  918.     GetItemRect(storage,iOrigColor,&origColorRect);
  919.  
  920.     inBox = true;
  921.     lastInBox = false;
  922.     
  923.     origTemp = (*storage)->origColor;
  924.     newTemp = (*storage)->color;
  925.     
  926.     do {
  927.         GetMouse(&where);
  928.         inBox = PtInRect(where,&origColorRect);
  929.         if(inBox != lastInBox)  {
  930.             lastInBox = inBox;
  931.             if(inBox)
  932.                 (*storage)->color = origTemp;
  933.             else
  934.                 (*storage)->color = newTemp;
  935.             SetSelectionColor(storage);
  936.             DrawColorRects(storage,true);
  937.             UpdateColorText(storage);
  938.             
  939.             if(data->colorProc)  {
  940.                 newColor.color = (*storage)->color.color;
  941.                 newColor.profile = 0L;
  942.                 data->colorProc(data->colorProcData,&newColor);
  943.             }
  944.         }
  945.     } while(Button());
  946.     if(inBox)  {
  947.         data->action = kColorChanged;
  948.         (*storage)->color = origTemp;
  949.     }
  950.     return err;
  951. }
  952.  
  953. /*
  954. *    Draws the color editor (for example, a color wheel). scrnInvalid specifies
  955. *    whether the screen itself is invalid, or we're just updating for a new color
  956. *    selection. This allows this routine to be used for more than just Window
  957. *    updates.
  958. */
  959. void DrawColorEditor(PickerStorageHndl storage,Boolean scrnInvalid)
  960. {
  961. #pragma unused(storage,scrnInvalid)
  962.  
  963.     // we don't do anything here in this example
  964. }
  965.  
  966. /*
  967. *    This routine redraws the entire original and new color rectangles. It is called
  968. *    when the dialog needs to be updated.
  969. */
  970. void DrawColorList(PickerStorageHndl storage)
  971. {
  972. Rect r;
  973. PenState oldPen;
  974.  
  975.     GetPenState(&oldPen);
  976.     PenNormal();
  977.     ForeColor(blackColor);
  978.     
  979.     GetItemRect(storage,iOrigColor,&r);
  980.     FrameRect(&r);
  981.     
  982.     GetItemRect(storage,iNewColor,&r);
  983.     FrameRect(&r);
  984.     
  985.     // now draw the interior of both the original and new color rectangles
  986.     DrawColorRects(storage,true);
  987.     
  988.     ForeColor(blackColor);
  989.     SetPenState(&oldPen);
  990. }
  991.  
  992. /*
  993. *    Draw the original and new color rectangles. We usually only draw the new color
  994. *    rectangle, so we have a boolean parameter for whether or not we want to draw
  995. *    the original color. Note that this routine only draws the interior of the
  996. *    rectangles. It is designed to be called inside a loop where the current color
  997. *    is being changed rapidly and not for entire dialog updates.
  998. */
  999. void DrawColorRects(PickerStorageHndl storage,Boolean drawOrig)
  1000. {
  1001. Rect r;
  1002.         
  1003.     PenNormal();
  1004.     GetItemRect(storage,iOrigColor,&r);
  1005.     InsetRect(&r,1,1);
  1006.     
  1007.     if(drawOrig)
  1008.         FillCRect(&r,(*storage)->origColorPat);
  1009.     
  1010.     GetItemRect(storage,iNewColor,&r);
  1011.     InsetRect(&r,1,1);
  1012.     
  1013.     FillCRect(&r,(*storage)->newColorPat);
  1014. }
  1015.  
  1016. /*
  1017. *    Take the current color and make a new RGB pattern for it
  1018. */
  1019. void SetSelectionColor(PickerStorageHndl storage)
  1020. {
  1021. RGBColor rgb;
  1022.     
  1023.     rgb = (*storage)->color.color.rgb;
  1024.     MakeRGBPat((*storage)->newColorPat,&rgb);
  1025.     
  1026.     DrawColorRects(storage,false);
  1027. }
  1028.  
  1029. /*
  1030. *    init the data we use for the script manager for our string conversion stuff
  1031. */
  1032. void InitNumerics(PickerStorageHndl storage)
  1033. {
  1034. Itl4Handle itl4;
  1035. StringHandle nString;
  1036. short resFile;
  1037.  
  1038.     resFile = OpenComponentResFile((Component) (*storage)->myself);
  1039.  
  1040.     itl4 = (Itl4Handle)IUGetIntl(4);
  1041.     
  1042.     if (itl4)  {
  1043.       (*storage)->nParts = *((NumberPartsPtr)( (char *)(*itl4) +
  1044.             ((*itl4)->defPartsOffset ) ) );
  1045.     } else
  1046.         DebugStr("\p unable to get default format");
  1047.     
  1048.     nString = GetString(kPercFormatString);
  1049.     if(!nString)
  1050.         DebugStr("\pCan't get format string");
  1051.  
  1052.     MoveHHi((Handle) storage);
  1053.     HLock((Handle) storage);
  1054.     MoveHHi((Handle) nString);
  1055.     HLock((Handle) nString);
  1056.     
  1057.     if(Str2Format(*nString,&(*storage)->nParts,&(*storage)->nFormat) != fFormatOK)
  1058.         DebugStr("Str2Format for nFormat failed");
  1059.     
  1060.     HUnlock((Handle) nString);
  1061.     ReleaseResource((Handle) nString);
  1062.  
  1063.     HUnlock((Handle) storage);
  1064.  
  1065.     CloseComponentResFile(resFile);
  1066. }
  1067.  
  1068.  
  1069.  
  1070. /*******************************************************************************************************
  1071. *
  1072. *        These are some utillity routines that make the dialog manager easier to work with.
  1073. *
  1074. *******************************************************************************************************/
  1075.  
  1076. /*
  1077. *    Return true if the given point is within the specified dialog item.
  1078. */
  1079. Boolean PtInItem(PickerStorageHndl storage, Point where, short itemNo)
  1080. {
  1081. Rect iBox;
  1082.  
  1083.     GetItemRect(storage,itemNo,&iBox);
  1084.     
  1085.     return PtInRect(where,&iBox);
  1086. }
  1087.  
  1088. /*
  1089. *    Get the rectangle for the specified item (itemNo is a local item number, so this routines
  1090. *    adds in the picker's base item number before calling GetDItem).
  1091. */
  1092. void GetItemRect(PickerStorageHndl storage,short itemNo,Rect *r)
  1093. {
  1094. Handle theItem;
  1095. short iType;
  1096.  
  1097.     GetDItem((*storage)->port,(*storage)->baseItem + itemNo,&iType,&theItem,r);
  1098. }
  1099.  
  1100. void SetItemRect(PickerStorageHndl storage,short itemNo,Rect *r)
  1101. {
  1102. Handle theItem;
  1103. short iType;
  1104. Rect iBox;
  1105.  
  1106.     GetDItem((*storage)->port,(*storage)->baseItem + itemNo,&iType,&theItem,&iBox);
  1107.     SetDItem((*storage)->port,(*storage)->baseItem + itemNo,iType,theItem,r);
  1108. }
  1109.  
  1110. void OffsetItemRect(PickerStorageHndl storage,short itemNo,short h,short v)
  1111. {
  1112. Handle theItem;
  1113. Rect r;
  1114. short iType;
  1115.  
  1116.     GetDItem((*storage)->port,(*storage)->baseItem + itemNo,&iType,&theItem,&r);
  1117.     
  1118.     OffsetRect(&r,h,v);
  1119.     SetDItem((*storage)->port,(*storage)->baseItem + itemNo,iType,theItem,&r);
  1120. }
  1121.  
  1122. Handle GetItemHandle(PickerStorageHndl storage,short theItem)
  1123. {
  1124. Handle itemH;
  1125. short iType;
  1126. Rect iBox;
  1127.  
  1128.     GetDItem((*storage)->port,(*storage)->baseItem + theItem,&iType,&itemH,&iBox);
  1129.     
  1130.     return itemH;
  1131. }
  1132.